package cn.cutie.clot.gateway.other;

import cn.cutie.clotrpc.core.api.LoadBalancer;
import cn.cutie.clotrpc.core.api.RegistryCenter;
import cn.cutie.clotrpc.core.cluster.RoundRobinLoadBalancer;
import cn.cutie.clotrpc.core.meta.InstanceMeta;
import cn.cutie.clotrpc.core.meta.ServiceMeta;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;

import java.util.List;

/**
 * @Description:
 * @Author: Cutie
 * @CreateDate: 2024/5/21 20:46
 * @Version: 0.0.1
 */
@Component
public class GatewayHandler {

    @Autowired
    RegistryCenter rc;

    LoadBalancer<InstanceMeta> loadBalancer = new RoundRobinLoadBalancer<>();


    Mono<ServerResponse> handle(ServerRequest request){
        // 1. 通过请求路径或者服务名
        String service = request.path().substring(4);
        ServiceMeta serviceMeta = ServiceMeta.builder()
                .name(service).app("app1").env("dev").namespace("public").build();
        // 2. 通过注册中心获取所有活着的实例
        List<InstanceMeta> instanceMetas = rc.fetchAll(serviceMeta);
        // 3. 获取实例的url
        String url = loadBalancer.choose(instanceMetas).toUrl();
        // 4. 拿到请求报文
        Mono<String> requestMono = request.bodyToMono(String.class);
        return requestMono.flatMap(s -> invokeFromRegistry(s, url));
    }

    private Mono<? extends ServerResponse> invokeFromRegistry(String s, String url) {
        // 5. 通过webclient发送post请求
        WebClient client = WebClient.create(url);
        Mono<ResponseEntity<String>> entity = client.post()
                .header("Content-Type", "application/json")
                .bodyValue(s)
                .retrieve()
                .toEntity(String.class);

        // 6. 获取响应报文
        Mono<String> body = entity.map(ResponseEntity::getBody);
        body.subscribe(souce -> System.out.println(souce));
        // 7. 返回响应报文
        return ServerResponse.ok()
                .header("Content-Type", "application/json")
                .header("clot.gw.version", "v1.0.0")
                .body(body, String.class);
    }
}
